#pragma once

#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <assert.h>
#include<cstdlib>
#include <unordered_map>
#include "../comm/util.hpp"
#include "../comm/log.hpp"

const std::string question_list = "./questions/question.list";
const std::string question_path = "./questions/";

namespace oj_model
{
    using namespace ns_log;
    using namespace ns_util;

    class Question
    {
    public:
        std::string _num;        // 问题的编号
        std::string _difficulty; // 问题的难度
        std::string _title;      // 问题的标题
        int _time;               // 问题的时间限制 s
        int _mem;                // 问题的空间限制 KB

        std::string _desc;   // 问题的描述
        std::string _header; // 问题的预设代码
        std::string _tail;   // 问题的测试用例
    };

    class Model
    {
    public:
        Model()
        {
            assert(LoadQuestionList(question_list));
        }

        bool LoadQuestionList(const std::string &question_list)
        {
            std::ifstream in(question_list);

            if (!in.is_open())
            {
                return false;
            }

            std::string line;
            while (getline(in, line))
            {
                std::vector<std::string> target;
                StringUtil::SplitString(line, target, " ");
                if (target.size() != 5)
                {
                    LOG(FATAL) << "get question list error!";
                    continue;
                }
                Question q;
                q._num = target[0];
                q._difficulty = target[1];
                q._title = target[2];
                q._time = atoi(target[3].c_str());
                q._mem = atoi(target[4].c_str());

                std::string path = question_path;
                path += q._num;

                FileUtil::ReadFile(path + "/desc.txt", &(q._desc), true);
                FileUtil::ReadFile(path + "/header.cpp", &(q._header), true);
                FileUtil::ReadFile(path + "/tail.cpp", &(q._tail), true);

                _questions.insert(std::make_pair(q._num, q));
            }

            in.close();
            return true;
        }

        bool GetAllQuestion(std::vector<Question> *out)
        {
            if (_questions.size() == 0)
            {
                LOG(ERROR) << "No questions";
                return false;
            }
            for (const auto &it : _questions)
            {
                out->push_back(it.second);
            }

            return true;
        }

        bool GetOneQuestion(std::string num, Question *q)
        {
            if (_questions.size() == 0)
            {
                LOG(ERROR) << "No questions";
                return false;
            }
            const auto &it = _questions.find(num);
            if (it == nullptr)
            {
                LOG(WARING) << "No such resalut";
                return false;
            }

            (*q) = it->second;
            return true;
        }

        ~Model() {}

    private:
        std::unordered_map<std::string, Question> _questions;
    };
}